/**
 * 敏感词接口
 */

import {
  directus,
  getItems,
  getItemById,
  createItem,
  updateItem,
  deleteItem,
} from "../directus";

/* ------------------------- 常量 & 类型 ------------------------- */

/** 集合名 */
export const COLLECTION_SENSATIVE = "sensative_words" as const;
export const COLLECTION_FIRST_NODE = "first_node" as const; // 一级分类
export const COLLECTION_SECOND_NODE = "second_node" as const; // 二级分类

/** 状态 */
export type SensativeWordStatus = "published" | "draft" | "archived";

/** 敏感词实体 */
export interface SensativeWord {
  id: number | string;
  sensative_word?: string; // 名称
  sensative_type?: string | number; // 处理方式（过滤 / 删除）
  status?: SensativeWordStatus; // 状态
  sort?: number | null;

  /** 关系字段 */
  firstcode?: null | { id: number | string; first_query?: string };
  secondnode?: null | { id: number | string; second_query?: string };

  date_created?: string | null;
  date_updated?: string | null;
  user_created?:
  | {
    id?: string | number;
    email?: string;
    first_name?: string;
    last_name?: string;
  }
  | null; // 添加人
  user_updated?: any;
}

/** 新增/更新入参 */
export interface CreateSensativeWordPayloadFull {
  sensative_word: string;
  sensative_type: string; // “过滤” / “删除”
  status: SensativeWordStatus;
  firstcode?: string | number | null; // 一级 id
  secondnode?: string | number | null; // 二级 id
}

/** 列表通用 */
const FIELDS_BASE = [
  "id",
  "sensative_word",
  "sensative_type",
  "status",
  "sort",
  "date_created",
  "date_updated",
  "user_created.id",
  "user_created.email",
  "user_created.first_name",
  "user_created.last_name",
  "firstcode.id",
  "firstcode.first_query",
  "secondnode.id",
  "secondnode.second_query",
] as const;
type FieldKey = (typeof FIELDS_BASE)[number];

/* ------------------------- 小工具 ------------------------- */

const normalizeSort = (sort?: string | string[]) =>
  Array.isArray(sort) ? sort.filter(Boolean) : sort ? [sort] : [];

const safeTrim = (s?: string) => (typeof s === "string" ? s.trim() : "");

const dateStamp = () => {
  const d = new Date();
  const p = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}_${p(
    d.getHours()
  )}${p(d.getMinutes())}${p(d.getSeconds())}`;
};

const toCsv = (rows: Array<Record<string, any>>, header: string[]) => {
  const esc = (v: any) => {
    const s = String(v ?? "");
    return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  const lines = [header, ...rows.map((r) => header.map((h) => r[h]))]
    .map((arr) => arr.map(esc).join(","))
    .join("\n");
  return "\uFEFF" + lines;
};

/** 公共筛选器 */
function buildFilter(args: {
  keyword?: string;
  excludeStatus?: SensativeWordStatus;
  ids?: Array<number | string>;
}) {
  const { keyword, excludeStatus, ids } = args || {};
  const filter: Record<string, any> = {};
  if (excludeStatus) filter.status = { _neq: excludeStatus };
  const kw = safeTrim(keyword);
  if (kw) filter._or = [{ sensative_word: { _icontains: kw } }];
  if (ids && ids.length) filter.id = { _in: ids };
  return filter;
}

/* ------------------------- 敏感词：列表/详情 ------------------------- */

/**
 * 列表
 */
export async function listSensativeWords(options?: {
  fields?: string[];
  page?: number;
  limit?: number;
  sort?: string | string[];
  filter?: Record<string, any>;
  meta?: ("filter_count" | "total_count")[];
  signal?: AbortSignal;
}) {
  const defaults = {
    fields: FIELDS_BASE as unknown as FieldKey[],
    page: 1,
    limit: 10,
    sort: ["id"],
    meta: ["filter_count", "total_count"] as ("filter_count" | "total_count")[],
  };
  return getItems<SensativeWord>(COLLECTION_SENSATIVE, {
    ...defaults,
    ...(options || {}),
    sort: normalizeSort(options?.sort ?? defaults.sort),
  });
}

/** 详情 */
export function getSensativeWordById(id: string | number, fields?: string[]) {
  const defaultFields = [...FIELDS_BASE];
  return getItemById<SensativeWord>(
    COLLECTION_SENSATIVE,
    id,
    fields && fields.length ? fields : (defaultFields as unknown as FieldKey[])
  );
}

/* ------------------------- 新增 / 更新 / 删除 / 批量删除 ------------------------- */

/** 新增 */
export function createSensativeWord(payload: CreateSensativeWordPayloadFull) {
  const body = {
    sensative_word: payload.sensative_word,
    sensative_type: payload.sensative_type,
    status: payload.status,
    firstcode: payload.firstcode ?? null,
    secondnode: payload.secondnode ?? null,
  };
  return createItem<SensativeWord>(COLLECTION_SENSATIVE, body);
}

/** 更新 */
export function updateSensativeWord(
  id: string | number,
  payload: Partial<CreateSensativeWordPayloadFull>
) {
  const body: Partial<CreateSensativeWordPayloadFull> = { ...payload };
  return updateItem<SensativeWord>(COLLECTION_SENSATIVE, id, body);
}

/** 删除（单个） */
export function removeSensativeWord(id: string | number) {
  return deleteItem(COLLECTION_SENSATIVE, id);
}

/** 批量删除 */
export async function removeSensativeWords(ids: (string | number)[]) {
  if (!ids || !ids.length) return;
  try {
    await directus.delete(`/items/${COLLECTION_SENSATIVE}`, {
      headers: { "Content-Type": "application/json" },
      data: { keys: ids },
    });
  } catch {
    await Promise.all(ids.map((id) => removeSensativeWord(id)));
  }
}

/* ------------------------- 状态（启用/停用） ------------------------- */

export function setSensativeStatus(
  id: string | number,
  status: SensativeWordStatus
) {
  return updateSensativeWord(id, { status });
}

export function enableSensativeWord(id: string | number) {
  return setSensativeStatus(id, "published");
}

export function disableSensativeWord(id: string | number) {
  return setSensativeStatus(id, "draft");
}

/* ------------------------- 一级分类 ------------------------- */

export interface FirstNode {
  id: number | string;
  first_query?: string;
}

/** 一级列表 */
export async function listFirstNodes(options?: {
  fields?: string[];
  page?: number;
  limit?: number;
  sort?: string | string[];
  filter?: Record<string, any>;
  meta?: ("filter_count" | "total_count")[];
  signal?: AbortSignal;
}) {
  const defaults = {
    fields: ["id", "first_query"],
    page: 1,
    limit: 1000,
    sort: ["id"],
  };
  return getItems<FirstNode>(COLLECTION_FIRST_NODE, {
    ...defaults,
    ...(options || {}),
    sort: normalizeSort(options?.sort ?? defaults.sort),
  });
}

/** 一级名称下拉 */
export async function getFirstNodeOptions(): Promise<string[]> {
  const { data } = await listFirstNodes({ limit: 1000 });
  return (data || [])
    .map((it) => String(it?.first_query ?? "").trim())
    .filter(Boolean);
}

/** 一级名称 -> id 映射 */
export async function getFirstNodeNameIdMap(): Promise<
  Record<string, string | number>
> {
  const { data } = await listFirstNodes({
    fields: ["id", "first_query"],
    limit: 1000,
  });
  const map: Record<string, string | number> = {};
  (data || []).forEach((it) => {
    const name = String(it?.first_query ?? "").trim();
    if (name) map[name] = it.id;
  });
  return map;
}

/* ------------------------- 二级分类 ------------------------- */

export interface SecondNode {
  id: number | string;
  second_query?: string;
  first_code?:
  | number
  | string
  | { id: number | string; first_query?: string };
}

/** 二级列表 */
export async function listSecondNodes(options?: {
  fields?: string[];
  page?: number;
  limit?: number;
  sort?: string | string[];
  filter?: Record<string, any>;
  meta?: ("filter_count" | "total_count")[];
  signal?: AbortSignal;
}) {
  const defaults = {
    fields: ["id", "second_query"],
    page: 1,
    limit: 25,
    sort: ["id"],
  };
  return getItems<SecondNode>(COLLECTION_SECOND_NODE, {
    ...defaults,
    ...(options || {}),
    sort: normalizeSort(options?.sort ?? defaults.sort),
  });
}

/** 用 first_code 的 id 精确过滤获取二级 */
function buildSecondListQueryStrict(args: {
  firstCodeId: string | number;
  page?: number;
  limit?: number;
  sort?: string | string[];
  fields?: string[];
  keyword?: string;
}) {
  const {
    firstCodeId,
    page = 1,
    limit = 25,
    sort = ["id"],
    fields = ["id", "second_query"],
    keyword,
  } = args;

  const usp = new URLSearchParams();
  usp.set("limit", String(limit));
  usp.set("page", String(page));
  (Array.isArray(sort) ? sort : [sort]).forEach((s) => usp.append("sort[]", s));
  fields.forEach((f) => usp.append("fields[]", f));
  usp.append("filter[_and][0][_and][0][first_code][_eq]", String(firstCodeId));
  const kw = safeTrim(keyword);
  if (kw) {
    usp.append("filter[_and][1][second_query][_contains]", kw);
  }
  return usp.toString();
}

export async function listSecondNodesByFirstCodeStrict(args: {
  firstCodeId: string | number;
  page?: number;
  limit?: number;
  sort?: string | string[];
  fields?: string[];
  keyword?: string;
}) {
  const url = `/items/${COLLECTION_SECOND_NODE}?${buildSecondListQueryStrict(
    args
  )}`;
  const res = await directus.get(url);
  return res.data as { data: SecondNode[]; meta?: any };
}

/** 根据一级 id 获取二级名称下拉 */
export async function getSecondNodeOptionsByFirstId(
  firstId?: string | number
) {
  if (firstId === undefined || firstId === null) return [];
  const { data } = await listSecondNodesByFirstCodeStrict({
    firstCodeId: firstId,
    limit: 1000,
    fields: ["id", "second_query"],
    sort: ["id"],
  });
  return (data || [])
    .map((it) => String(it?.second_query ?? "").trim())
    .filter(Boolean);
}

/** 根据一级名称获取二级名称下拉 */
export async function getSecondNodeOptions(firstName?: string) {
  if (!firstName) return [];
  const map = await getFirstNodeNameIdMap();
  const id = map[firstName];
  if (id === undefined) return [];
  return getSecondNodeOptionsByFirstId(id);
}

/* ------------------------- 导入 ------------------------- */
export async function importSensativeWords(
  items: CreateSensativeWordPayloadFull[],
  chunkSize = 100
) {
  if (!items || !items.length) return;
  for (let i = 0; i < items.length; i += chunkSize) {
    const slice = items.slice(i, i + chunkSize);
    await directus.post(`/items/${COLLECTION_SENSATIVE}`, slice, {
      headers: { "Content-Type": "application/json; charset=utf-8" },
    });
  }
}

/* ------------------------- 导出------------------------- */

export interface ExportSensativeParams {
  ids?: Array<number | string>;
  keyword?: string;
  excludeStatus?: SensativeWordStatus;
  sort?: string | string[];
  format?: "csv" | "json";
  signal?: AbortSignal;
}
export async function exportSensativeWords(params: ExportSensativeParams = {}) {
  const {
    ids,
    keyword = "",
    excludeStatus = "archived",
    sort = ["-id"],
    format = "csv",
    signal,
  } = params;

  const exportFields = [
    "id",
    "sensative_word",
    "sensative_type",
    "status",
    "sort",
    "date_created",
    "firstcode.first_query",
    "secondnode.second_query",
  ] as const;

  const filter = buildFilter({ excludeStatus, keyword, ids });
  const limit = 500;
  let page = 1;
  const all: SensativeWord[] = [];

  while (true) {
    const res: any = await getItems<SensativeWord>(COLLECTION_SENSATIVE, {
      page,
      limit,
      fields: exportFields as unknown as string[],
      sort: normalizeSort(sort),
      filter,
      signal,
    });
    const chunk: SensativeWord[] = res?.data ?? res ?? [];
    all.push(...chunk);
    if (!chunk.length || chunk.length < limit) break;
    page += 1;
  }

  const rows = all.map((x) => ({
    id: x.id,
    sensative_word: x.sensative_word || "",
    sensative_type: x.sensative_type ?? "",
    status: x.status || "draft",
    sort: x.sort ?? "",
    firstcode_first_query: x.firstcode?.first_query ?? "",
    secondnode_second_query: x.secondnode?.second_query ?? "",
    date_created: x.date_created ?? "",
  }));

  const stamp = dateStamp();

  if (format === "json") {
    const blob = new Blob([JSON.stringify(rows, null, 2)], {
      type: "application/json;charset=utf-8",
    });
    return {
      blob,
      filename: `sensative_words_${stamp}_${rows.length}.json`,
      count: rows.length,
    };
  }

  const header = [
    "id",
    "sensative_word",
    "sensative_type",
    "status",
    "sort",
    "firstcode_first_query",
    "secondnode_second_query",
    "date_created",
  ];
  const csv = toCsv(rows as any[], header);

  const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
  return {
    blob,
    filename: `sensative_words_${stamp}_${rows.length}.csv`,
    count: rows.length,
  };
}
